package com.jnevision.clockin.task;

import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.jnevision.attendancegroup.model.AttendanceGroup;
import com.jnevision.attendancegroup.service.AttendanceGroupServiceImpl;
import com.jnevision.clockin.model.ClockIn;
import com.jnevision.clockin.service.ClockInServiceImpl;
import com.jnevision.leave.model.LeaveVO;
import com.jnevision.leave.service.LeaveServiceImpl;
import com.jnevision.personalattendance.model.PersonalAttendance;
import com.jnevision.personalattendance.service.PersonalAttendanceServiceImpl;
import com.jnevision.salary.model.Salary;
import com.jnevision.salary.service.SalaryServiceImpl;
import com.jnevision.salaryrecord.model.SalaryRecord;
import com.jnevision.salaryrecord.service.SalaryRecordServiceImpl;
import com.jnevision.sysconfig.service.ConfigServiceImpl;
import com.jnevision.user.model.User;
import com.jnevision.user.service.UserServiceImpl;
import com.jnevision.userdept.model.UserDept;
import com.jnevision.userdept.service.UserDeptServiceImpl;

@Component
@Configuration
@EnableScheduling
public class ClockInTask {
    @Autowired
    private LeaveServiceImpl leaveServiceImpl;
    @Autowired
    private UserServiceImpl userServiceImpl;
    @Autowired
    private SalaryServiceImpl salaryServiceImpl;
    @Autowired
    private UserDeptServiceImpl userDeptServiceImpl;
    @Autowired
    private ClockInServiceImpl clockInServiceImpl;

    @Autowired
    private AttendanceGroupServiceImpl attendanceGroupServiceImpl;
    @Autowired
    private PersonalAttendanceServiceImpl personalAttendanceServiceImpl;
    @Autowired
    private ConfigServiceImpl configServiceImpl;
    @Autowired
    private SalaryRecordServiceImpl salaryRecordServiceImpl;

    // TODO 补卡，请假请更新打卡状态
    // TODO 考勤状态汇总，定时任务一天一次,不存在跨天的问题了，保安考勤没有了;计算请假，迟到，旷工等的时间
    @Scheduled(cron = "0 0 0 * * ?")
    // @Scheduled(cron = "0 * * * * ?")
    public void attendanceStatistics() {
        /*
         * 迟到----------看有没有请假, TODO 看昨天有没有相应的加班时间，如果有也不算迟到
         * 旷工----------看有没有请假
         * 早退----------看有没有请假
         * 缺卡----------看有没有请假
         * 打卡
         * 请假---有请假记录，暂不统计
         */
        List<User> userList = this.userServiceImpl.list(new QueryWrapper<User>().eq("is_valid", 1)); // 所有在职员工
        String yesterday = LocalDate.now().minusDays(1).toString();
        // String yesterday = "2019-08-18";
        for (User user : userList) {
            // 根据用户查询所在的部门
            // 根据部门查询部门的上下班时间
            // 根据上下班时间和打卡时间，判断是否早退，迟到
            // 根据当天是否休息判断是否缺卡，旷工

            UserDept ud = this.userDeptServiceImpl.getOne(new QueryWrapper<UserDept>().eq("user_id", user.getId()));
            AttendanceGroup group = this.attendanceGroupServiceImpl.getOne(new QueryWrapper<AttendanceGroup>()
                .eq("dept_id", ud.getDeptId()).eq("attendance_cycle", yesterday.substring(0, 7)));

            if (group == null) {
                System.err.println(ud.getDeptId() + "》》》部门没有考勤组配置");
                continue;
            }

            String start = yesterday + " " + group.getMorningStart() + ":00"; // 迟到依据
            String end = yesterday + " " + group.getAfternoonEnd() + ":00"; // 早退依据

            ClockIn clockIn = this.clockInServiceImpl
                .getOne(new QueryWrapper<ClockIn>().eq("work_day", yesterday).eq("user_id", user.getId())); // 打卡记录
            PersonalAttendance attendance = this.personalAttendanceServiceImpl.getOne(
                new QueryWrapper<PersonalAttendance>().eq("group_id", group.getId()).eq("user_id", user.getId())); // 排班记录，是否休息

            if (attendance == null) {
                System.out.println(user.getId() + "没有人员排班计划， 请排班");
                continue;
            }

            if (clockIn == null) {
                // 1<x>2 ;1 12:00:00 ;17:00:00 小于开始，大于结束2-8 <= 2-8 2-17 <= 3-17
                clockIn = new ClockIn();
                clockIn.setUserId(user.getId());
                clockIn.setWorkDay(yesterday);
                clockIn.setFaceCode(Optional.ofNullable(user.getFaceCode()).orElse(""));
                List<LeaveVO> leaveList = this.leaveServiceImpl.leaveFinished(user.getId(), start, end);
                if (CollectionUtils.isEmpty(leaveList)
                    && attendance.getDays()[Integer.parseInt(yesterday.substring(8)) - 1].equals("√")) {
                    clockIn.setClockInStatus(5); // 旷工
                    // 插入一条旷工数据
                } else if (CollectionUtils.isEmpty(leaveList)
                    && attendance.getDays()[Integer.parseInt(yesterday.substring(8)) - 1].equals("休")) {
                    clockIn.setClockInStatus(8); // 休息
                    // 插入一条休息数据
                } else if (leaveList.size() >= 1) {
                    clockIn.setClockInStatus(2); // 请假
                    // 请假的时候直接插入一条请假的数据
                }

                this.clockInServiceImpl.save(clockIn);
                continue;
            } else if (StringUtils.isEmpty(clockIn.getWorkShift())) {
                clockIn.setClockInStatus(3); // 上午缺卡
                this.clockInServiceImpl.updateById(clockIn);
            } else if (StringUtils.isEmpty(clockIn.getClosingTime())) {
                clockIn.setClockInStatus(9); // 下午缺卡
                this.clockInServiceImpl.updateById(clockIn);
            } else {
                List<LeaveVO> laterList = this.leaveServiceImpl.leaveFinished(user.getId(), start, start);

                if (StringUtils.compare(clockIn.getWorkShift(), start, true) > 0
                    && CollectionUtils.isEmpty(laterList)) {
                    clockIn.setClockInStatus(1); // 迟到
                }

                List<LeaveVO> earlyList = this.leaveServiceImpl.leaveFinished(user.getId(), end, end);
                if (StringUtils.compare(clockIn.getClosingTime(), end, true) < 0
                    && CollectionUtils.isEmpty(earlyList)) {
                    if (clockIn.getClockInStatus() == 1) {
                        clockIn.setClockInStatus(6); // 迟到早退
                    } else {
                        clockIn.setClockInStatus(4); // 早退
                    }
                }

                this.clockInServiceImpl.updateById(clockIn);
                continue;
            }
            // 两头都打卡，判断是否在正常时间内或请假，否则迟到或早退
            // 两头都不打卡判断是否休息，请假，否则为旷工
            // 一头打卡，为缺卡
            // clockIn.getWorkShift()
        }
        // 查询员工的考勤计划
        // 根据签到时间，计算出是否迟到
        // 根据签退时间，计算出是否早退，是否缺卡
        // 根据签到签退，计算出是否旷工
        // 其余的为正常打卡，和请假
    }

    // 工龄的增长
    @Scheduled(cron = "0 0 0 1 1 ?")
    // @Scheduled(cron = "0 * * * * ?")
    public void workYear() {
        // 从入职日期开始计算，够完整一年的就把工龄增长十元
        // 查询所有在职员工
        List<User> list = this.userServiceImpl.list(new QueryWrapper<User>().eq("is_signing", 1));
        for (User user : list) {
            if (user.isAnnualSalary() != null && user.isAnnualSalary()) {
                continue; // 如果是年薪则不计算工龄工资
            }
            // sys_user (当前-entry_time)/ 365 对比 b_salary gongling，如果到一年的时间的话给 b_salary gongling增加10元
            // 10元为配置表里的数据，sys_config自定义
            String gonglingMoney = this.configServiceImpl.getValue("gongling");
            LocalDate now = LocalDate.now();

            LocalDate entryTiem = LocalDate.parse(user.getEntryTime());

            int years = now.getYear() - entryTiem.getYear();

            int gongling = 0;
            if (years != 0) {
                gongling = (years + 1) * Integer.valueOf(gonglingMoney);
            }

            Salary salary = this.salaryServiceImpl.getOne(new QueryWrapper<Salary>().eq("user_id", user.getId()));

            if (StringUtils.isEmpty(salary.getGongling()) || !Integer.toString(gongling).equals(salary.getGongling())) {

                salary.setGongling(Long.toString(gongling));
                this.salaryServiceImpl.update(salary, new UpdateWrapper<Salary>().eq("user_id", salary.getUserId()));
                SalaryRecord record = this.salaryRecordServiceImpl.getOne(
                    new QueryWrapper<SalaryRecord>().eq("user_id", user.getId()).orderByDesc("date").last("limit 1"));
                if (!Objects.isNull(record)) {
                    record.setGongling(salary.getGongling());
                    this.salaryRecordServiceImpl.updateById(record);
                }
            }
        }
    }
}
